package com.obaamilos.accesscontrol;

/**
 * @author Pedro R. Oliveira
 *
 */

//import java.util.*;

import jade.core.*;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.util.Logger;

//import com.obaamilos.accesscontrol.ExecutaVerificacaoAcesso;

public class AgenteAC extends Agent {

	/**
	 * Serial gerado pelo Eclipse
	 */
	private static final long serialVersionUID = -4445221082572610986L;
	private AID[] agentesQry;
	private MessageTemplate mt;   // Template para receber respostas
	private VerificacaoAcesso mAC;
	private Logger myLogger = Logger.getMyLogger(getClass().getName());
	private String strLocalTDB;

	private class EsperaConsultaEResponde extends CyclicBehaviour {

		/**
		 * Serial gerado pelo Eclipse
		 */
		private static final long serialVersionUID = 1429633604522268579L;
		//private static final long serialVersionUID = 7016064047780333582L;
		
		public EsperaConsultaEResponde(Agent a) {
			super(a);
		}

		public void action() {
			ACLMessage msg = myAgent.receive();
			if (msg != null) {
				ACLMessage reply = msg.createReply();

				if (msg.getPerformative()== ACLMessage.REQUEST) {
					String conteudo = msg.getContent();

					System.out.println("AgenteAccessControl recebeu mensagem '" + conteudo + "'");
					
					String [] params;
					String strRet = "";
					
					params = conteudo.split("<aa>");
					String solicitacao = "";
					String Param1 = "";    // Login name ou Token
					String Param2 = "";    // Password ou A��o requisitada
					String Param3 = "";    // Vazio ou Recurso
					if (params.length > 1)  {
						solicitacao = params[0].toUpperCase();  // Login ou Acesso

						Param1 = params[1];          // Login name ou Token
						if (params.length > 2)  {
							Param2 = params[2];      // Password ou A��o requisitada
							if (params.length > 3)  {
								Param3 = params[3];  // Vazio ou Recurso
							}
						}
					}

					//System.out.println("AgenteQuery recebeu mensagem '" + conteudo + "'");
					System.out.println("Executando verifica��o de acesso...");
					System.out.println("Solicita��o '" + solicitacao + "'");
					System.out.println("Param 1 '" + Param1 + "'");
					System.out.println("Param 2 '" + Param2 + "'");
					System.out.println("Param 3 '" + Param3 + "'");

					if (solicitacao.equals("LOGIN")) {
						strRet = buscaUsuarioPerfil(Param1, Param2);
						if (strRet.length() > 1) {
							strRet = mAC.logaUsuario(strRet);
						}
			        }
					else {
						if (solicitacao.equals("TDB")) {
							strRet = Param1;
							strLocalTDB = Param1;
						}
						else {
							if (solicitacao.equals("USER")) {
								// Retorna o usu�rio
								Usuario mUsuAux = mAC.obtemUsuario(Param1);
								if (mUsuAux != null) {
									strRet = mUsuAux.toString();
								}
								else
									strRet = "";
							}
							else {
								// acesso ou logout
								strRet = mAC.run(solicitacao, Param1, Param2, Param3);
							}
						}
					}

					reply.setPerformative(ACLMessage.INFORM);
					
                    if (strRet.length() > 0) {
                    	reply.setContent(strRet);
                        System.out.println("Resp OK");
                    }
                    else {
                    	reply.setContent("");
                        System.out.println("Resp NOK");
                    }

                    send(reply);
                    System.out.println("AgenteAC enviou mensagem a " + msg.getSender().getName());
				}
			}
			else {
				block();
			}
		}
		
		private String buscaUsuarioPerfil(String pLogin, String pSenha) {
			String mRetorno = "";
			// Se for login...
			ACLMessage req = new ACLMessage(ACLMessage.REQUEST);
			System.out.println("Agentes query login..."+Integer.toString(agentesQry.length));
			if (agentesQry.length > 0) {
				req.addReceiver(agentesQry[0]);
				System.out.println("Query selecionou agente " + agentesQry[0].getName());
				req.setContent(strLocalTDB+"<separa>"+System.getProperty("line.separator")+
						"PREFIX ca: <http://www.semanticweb.org/controle_acesso#>"+System.getProperty("line.separator")+
						"SELECT *"+System.getProperty("line.separator")+
						"WHERE { ?u a ca:User . ?u ca:nameIs ?n . ?u ca:loginIs \""+pLogin+"\"^^<http://www.w3.org/2001/XMLSchema#string> . ?u ca:passwordIs \""+pSenha+"\"^^<http://www.w3.org/2001/XMLSchema#string> . ?u ca:hasAccess ?a . ?a ca:hasResource ?r . ?a ca:hasAction ?g }");
				req.setConversationId("login-query");
				req.setReplyWith("req"+System.currentTimeMillis()); // Valor �nico
				send(req);
				System.out.println("Query enviada");

				// Prepara "template" para receber respostas
				mt = MessageTemplate.and(MessageTemplate.MatchConversationId("login-query"),
						MessageTemplate.MatchPerformative(ACLMessage.INFORM));

				ACLMessage resposta = blockingReceive(mt);
				if (resposta != null) {
					// Conjunto local do agentes recebido
					//System.out.println("Teste Recebeu resposta n�o nula");
					if (resposta.getPerformative() == ACLMessage.INFORM) {
						// Grava o retorno...
						System.out.println("Retornou da query com conte�do");
						String strResposta;
						strResposta = resposta.getContent();
						String [] strRegistros = strResposta.split(System.getProperty("line.separator"));
						if (strRegistros.length > 1)  {
							String [] Campos = strRegistros[1].split(", ");
							if (Campos.length > 4) {
								mRetorno = Campos[1]+"<aa>"+pLogin+"<aa>"+Campos[3]+"<cc>"+Campos[4].replace("]", "")+"<bb>";
							}
							for (int x = 2; x < strRegistros.length; x++) {
								Campos = strRegistros[x].split(", ");
								if (Campos.length > 4) {
									mRetorno += Campos[3]+"<cc>"+Campos[4].replace("]", "")+"<bb>";
								}
							}
						}
					}
				}
			}
			return mRetorno;
		}
	}

	protected void setup() {
		// Aguarda agentes Query/Update subirem...
		try {
		    Thread.sleep(1000);
		} catch(InterruptedException ex) {
		    Thread.currentThread().interrupt();
		}		
		// Obtem todos os agentes do ambiente que sejam do tipo AgenteQuery
		DFAgentDescription template_qry = new DFAgentDescription();
		ServiceDescription sd_qry = new ServiceDescription();
		sd_qry.setType("AgenteQuery");
		template_qry.addServices(sd_qry);
		try {
			DFAgentDescription[] result = DFService.search(this, template_qry); 
			System.out.println("Encontrados os agentes query:");
			agentesQry = new AID[result.length];
			for (int i = 0; i < result.length; ++i) {
				agentesQry[i] = result[i].getName();
				System.out.println(agentesQry[i].getName());
			}
		}
		catch (FIPAException fe) {
			fe.printStackTrace();
		}
		
		// Cria a classe do controle de usu�rios
		mAC = new VerificacaoAcesso();
		
		// Registra-se no DF Como AgenteQuery Verificador Armazenador

		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(getAID());
		ServiceDescription sd = new ServiceDescription();   
		sd.setType("AgenteAccessControl"); 
		sd.setName(getName());
		dfd.addServices(sd);
		try {
			DFService.register(this,dfd);
			EsperaConsultaEResponde AgenteACBehaviour = new EsperaConsultaEResponde(this);
			addBehaviour(AgenteACBehaviour);
		} catch (FIPAException e) {
			myLogger.log(Logger.SEVERE, "Agente "+getLocalName()+" - N�o conseguiu registrar-se ao DF", e);
			doDelete();
		}
	}
}
